home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / var / lib / python-support / python2.6 / glchess / ai.pyc (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2009-04-20  |  14.0 KB  |  523 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. __author__ = 'Robert Ancell <bob27@users.sourceforge.net>'
  5. __license__ = 'GNU General Public License Version 2'
  6. __copyright__ = 'Copyright 2005-2006  Robert Ancell'
  7. import os
  8. import sys
  9. import select
  10. import signal
  11. import xml.dom.minidom as xml
  12. import xml.parsers.expat as xml
  13. import game
  14. import cecp
  15. import uci
  16. from defaults import *
  17. CECP = 'CECP'
  18. UCI = 'UCI'
  19.  
  20. class Option:
  21.     '''
  22.     '''
  23.     value = ''
  24.  
  25.  
  26. class Level:
  27.     '''
  28.     '''
  29.     
  30.     def __init__(self):
  31.         self.options = []
  32.  
  33.  
  34.  
  35. class Profile:
  36.     '''
  37.     '''
  38.     
  39.     def __init__(self):
  40.         self.name = ''
  41.         self.protocol = ''
  42.         self.path = ''
  43.         self.executables = []
  44.         self.arguments = []
  45.         self.profiles = { }
  46.  
  47.     
  48.     def detect(self):
  49.         '''
  50.         '''
  51.         
  52.         try:
  53.             path = os.environ['PATH'].split(os.pathsep)
  54.         except KeyError:
  55.             path = []
  56.  
  57.         for directory in path:
  58.             for executable in self.executables:
  59.                 b = directory + os.sep + executable
  60.                 if os.path.isfile(b):
  61.                     self.path = b
  62.                     return None
  63.             
  64.         
  65.         self.path = None
  66.  
  67.  
  68.  
  69. def _getXMLText(node):
  70.     '''
  71.     '''
  72.     if len(node.childNodes) == 0:
  73.         return ''
  74.     if len(node.childNodes) > 1 or node.childNodes[0].nodeType != node.TEXT_NODE:
  75.         raise ValueError
  76.     node.childNodes[0].nodeType != node.TEXT_NODE
  77.     return node.childNodes[0].nodeValue
  78.  
  79.  
  80. def _loadLevel(node):
  81.     '''
  82.     '''
  83.     level = Level()
  84.     n = node.getElementsByTagName('name')
  85.     if len(n) != 1:
  86.         return None
  87.     level.name = _getXMLText(n[0])
  88.     for e in node.getElementsByTagName('option'):
  89.         option = Option()
  90.         option.value = _getXMLText(e)
  91.         
  92.         try:
  93.             attribute = e.attributes['name']
  94.         except KeyError:
  95.             len(n) != 1
  96.             len(n) != 1
  97.         except:
  98.             len(n) != 1
  99.  
  100.         option.name = _getXMLText(attribute)
  101.         level.options.append(option)
  102.     
  103.     return level
  104.  
  105.  
  106. def loadProfiles():
  107.     '''
  108.     '''
  109.     profiles = []
  110.     fileNames = [
  111.         os.path.expanduser(LOCAL_AI_CONFIG),
  112.         os.path.join(BASE_DIR, 'ai.xml'),
  113.         'ai.xml']
  114.     document = None
  115.     for f in fileNames:
  116.         
  117.         try:
  118.             document = xml.dom.minidom.parse(f)
  119.         except IOError:
  120.             continue
  121.             except xml.parsers.expat.ExpatError:
  122.                 print 'AI configuration from %s is invalid, ignoring' % f
  123.                 continue
  124.             else:
  125.                 break
  126.         if document is None:
  127.             print 'WARNING: No AI configuration'
  128.             return profiles
  129.         elements = document.getElementsByTagName('aiconfig')
  130.         if len(elements) == 0:
  131.             return profiles
  132.         for e in elements:
  133.             for p in e.getElementsByTagName('ai'):
  134.                 
  135.                 try:
  136.                     protocolName = p.attributes['type'].nodeValue
  137.                 except KeyError:
  138.                     len(elements) == 0
  139.                     len(elements) == 0
  140.                     document is None
  141.                     if not False:
  142.                         raise AssertionError
  143.                 except:
  144.                     False
  145.  
  146.                 if protocolName == 'cecp':
  147.                     protocol = CECP
  148.                 elif protocolName == 'uci':
  149.                     protocol = UCI
  150.                 elif not False:
  151.                     raise AssertionError, 'Uknown AI type: %s' % repr(protocolName)
  152.                 n = p.getElementsByTagName('name')
  153.                 if not len(n) > 0:
  154.                     raise AssertionError
  155.                 name = _getXMLText(n[0])
  156.                 executables = []
  157.                 n = p.getElementsByTagName('binary')
  158.                 if not len(n) > 0:
  159.                     raise AssertionError
  160.                 for x in n:
  161.                     executables.append(_getXMLText(x))
  162.                 
  163.                 arguments = []
  164.                 for x in p.getElementsByTagName('argument'):
  165.                     arguments.append(_getXMLText(x))
  166.                 
  167.                 levels = { }
  168.                 for x in p.getElementsByTagName('level'):
  169.                     level = _loadLevel(x)
  170.                     if level is not None:
  171.                         levels[level.name] = level
  172.                         continue
  173.                     len(n) > 0
  174.                 
  175.                 profile = Profile()
  176.                 profile.name = name
  177.                 profile.protocol = protocol
  178.                 profile.executables = executables
  179.                 profile.arguments = arguments
  180.                 profile.levels = levels
  181.                 profiles.append(profile)
  182.             
  183.         
  184.  
  185.     return profiles
  186.  
  187.  
  188. class CECPConnection(cecp.Connection):
  189.     '''
  190.     '''
  191.     
  192.     def __init__(self, player):
  193.         '''
  194.         '''
  195.         self.player = player
  196.         cecp.Connection.__init__(self)
  197.  
  198.     
  199.     def onOutgoingData(self, data):
  200.         '''Called by cecp.Connection'''
  201.         self.player.logText(data, 'output')
  202.         self.player.sendToEngine(data)
  203.  
  204.     
  205.     def onMove(self, move):
  206.         '''Called by cecp.Connection'''
  207.         if self.player.isReadyToMove():
  208.             self.player.moving = True
  209.             self.player.move(move)
  210.         elif not self.player.suppliedMove is None:
  211.             raise AssertionError
  212.         self.player.suppliedMove = move
  213.  
  214.     
  215.     def logText(self, text, style):
  216.         '''Called by cecp.Connection'''
  217.         self.player.logText(text, style)
  218.  
  219.  
  220.  
  221. class UCIConnection(uci.StateMachine):
  222.     '''
  223.     '''
  224.     
  225.     def __init__(self, player):
  226.         '''
  227.         '''
  228.         self.player = player
  229.         uci.StateMachine.__init__(self)
  230.  
  231.     
  232.     def onOutgoingData(self, data):
  233.         '''Called by uci.StateMachine'''
  234.         self.player.logText(data, 'output')
  235.         self.player.sendToEngine(data)
  236.  
  237.     
  238.     def logText(self, text, style):
  239.         '''Called by uci.StateMachine'''
  240.         self.player.logText(text, style)
  241.  
  242.     
  243.     def onMove(self, move):
  244.         '''Called by uci.StateMachine'''
  245.         self.player.move(move)
  246.  
  247.  
  248.  
  249. def _cDied(sig, stackFrame):
  250.     
  251.     try:
  252.         (pid, status) = os.waitpid(-1, os.WNOHANG)
  253.     except OSError:
  254.         pass
  255.  
  256.  
  257. signal.signal(signal.SIGCHLD, _cDied)
  258.  
  259. class Player(game.ChessPlayer):
  260.     '''
  261.     '''
  262.     
  263.     def __init__(self, name, profile, level = 'normal'):
  264.         """Constructor for an AI player.
  265.         
  266.         'name' is the name of the player (string).
  267.         'profile' is the profile to use for the AI (Profile).
  268.         'level' is the difficulty level to use (string).
  269.         """
  270.         self._Player__profile = profile
  271.         self._Player__level = level
  272.         self.moving = False
  273.         self.suppliedMove = None
  274.         game.ChessPlayer.__init__(self, name)
  275.         (toManagerOutput, toManagerInput) = os.pipe()
  276.         (fromManagerOutput, fromManagerInput) = os.pipe()
  277.         self._Player__toEngineFd = toManagerInput
  278.         self._Player__fromEngineFd = fromManagerOutput
  279.         
  280.         try:
  281.             self._Player__pid = os.fork()
  282.         except OSError:
  283.             e = None
  284.             print 'Monitor failed to fork: %s' % e.message
  285.             os.close(toManagerInput)
  286.             os.close(toManagerOutput)
  287.             os.close(fromManagerInput)
  288.             os.close(fromManagerOutput)
  289.             self._Player__toEngineFd = None
  290.             self._Player__fromEngineFd = None
  291.  
  292.         if self._Player__pid == 0:
  293.             os.close(toManagerInput)
  294.             os.close(fromManagerOutput)
  295.             self._runMonitor(fromManagerInput, toManagerOutput)
  296.             os.close(toManagerOutput)
  297.             os.close(fromManagerInput)
  298.             os._exit(0)
  299.         
  300.         os.close(toManagerOutput)
  301.         os.close(fromManagerInput)
  302.         if profile.protocol == CECP:
  303.             self.connection = CECPConnection(self)
  304.         elif profile.protocol == UCI:
  305.             self.connection = UCIConnection(self)
  306.         elif not False:
  307.             raise AssertionError
  308.         self.connection.start()
  309.         self.connection.startGame()
  310.         
  311.         try:
  312.             level = self._Player__profile.levels[self._Player__level]
  313.         except KeyError:
  314.             self.connection.configure()
  315.  
  316.         self.connection.configure(level.options)
  317.  
  318.     
  319.     def logText(self, text, style):
  320.         '''
  321.         '''
  322.         pass
  323.  
  324.     
  325.     def getProfile(self):
  326.         '''Get the AI profile this AI is using.
  327.         
  328.         Returns a 2-tuple containing the profile name (str) and the difficulty level (str).
  329.         '''
  330.         return (self._Player__profile.name, self._Player__level)
  331.  
  332.     
  333.     def fileno(self):
  334.         '''Returns the file descriptor for communicating with the engine (integer)'''
  335.         return self._Player__fromEngineFd
  336.  
  337.     
  338.     def read(self):
  339.         '''Read and process data from the engine.
  340.         
  341.         This is non-blocking.
  342.         '''
  343.         while True:
  344.             if self._Player__fromEngineFd == None:
  345.                 return False
  346.             (rlist, _, xlist) = select.select([
  347.                 self._Player__fromEngineFd], [], [
  348.                 self._Player__fromEngineFd], 0)
  349.             if len(rlist) + len(xlist) == 0:
  350.                 return True
  351.             
  352.             try:
  353.                 data = os.read(self._Player__fromEngineFd, 256)
  354.             except OSError:
  355.                 len(rlist) + len(xlist) == 0
  356.                 e = len(rlist) + len(xlist) == 0
  357.                 self._Player__fromEngineFd == None
  358.                 print 'Error reading from chess engine: ' + str(e)
  359.                 self._die()
  360.                 return False
  361.  
  362.             if len(data) == 0:
  363.                 print 'Engine has died'
  364.                 self._die()
  365.                 return False
  366.             self.connection.registerIncomingData(data)
  367.             continue
  368.             len(data) == 0
  369.  
  370.     
  371.     def sendToEngine(self, data):
  372.         '''
  373.         '''
  374.         if self._Player__toEngineFd == None:
  375.             return None
  376.         
  377.         try:
  378.             os.write(self._Player__toEngineFd, data)
  379.         except OSError:
  380.             self._Player__toEngineFd == None
  381.             e = self._Player__toEngineFd == None
  382.             print 'Failed to write to engine: ' + str(e)
  383.         except:
  384.             self._Player__toEngineFd == None
  385.  
  386.  
  387.     
  388.     def quit(self):
  389.         '''Disconnect the AI'''
  390.         fd = self._Player__toEngineFd
  391.         self._Player__toEngineFd = None
  392.         self._Player__fromEngineFd = None
  393.         
  394.         try:
  395.             if fd is not None:
  396.                 os.write(fd, '\nquit\n')
  397.         except OSError:
  398.             return None
  399.  
  400.  
  401.     
  402.     def onPlayerMoved(self, player, move):
  403.         '''Called by game.ChessPlayer'''
  404.         if self._Player__toEngineFd == None:
  405.             return None
  406.         if player is self:
  407.             pass
  408.         isSelf = self.moving
  409.         self.moving = False
  410.         self.connection.reportMove(move.canMove, isSelf)
  411.  
  412.     
  413.     def onUndoMove(self):
  414.         '''Called by game.ChessPlayer'''
  415.         self.connection.undoMove()
  416.  
  417.     
  418.     def readyToMove(self):
  419.         '''Called by game.ChessPlayer'''
  420.         if self._Player__toEngineFd == None:
  421.             self.die()
  422.             return None
  423.         game = self.getGame()
  424.         whiteTime = game.getWhite().getRemainingTime()
  425.         blackTime = game.getBlack().getRemainingTime()
  426.         if game.getWhite() is self:
  427.             ownTime = whiteTime
  428.         else:
  429.             ownTime = blackTime
  430.         if self.suppliedMove is None:
  431.             self.connection.requestMove(whiteTime, blackTime, ownTime)
  432.         else:
  433.             self.moving = True
  434.             move = self.suppliedMove
  435.             self.suppliedMove = None
  436.             self.move(move)
  437.  
  438.     
  439.     def onGameEnded(self, game):
  440.         '''Called by game.ChessPlayer'''
  441.         self.quit()
  442.  
  443.     
  444.     def _die(self):
  445.         self.quit()
  446.         self.die()
  447.  
  448.     
  449.     def _runEngine(self, toEngineFd, fromEngineFd):
  450.         os.nice(19)
  451.         
  452.         try:
  453.             os.mkdir(LOG_DIR)
  454.         except OSError:
  455.             pass
  456.  
  457.         
  458.         try:
  459.             os.chdir(LOG_DIR)
  460.         except OSError:
  461.             pass
  462.  
  463.         os.dup2(toEngineFd, sys.stdin.fileno())
  464.         os.dup2(fromEngineFd, sys.stdout.fileno())
  465.         os.dup2(fromEngineFd, sys.stderr.fileno())
  466.         
  467.         try:
  468.             os.execv(self._Player__profile.path, [
  469.                 self._Player__profile.path] + self._Player__profile.arguments)
  470.         except OSError:
  471.             pass
  472.  
  473.  
  474.     
  475.     def _runMonitor(self, toApplicationFd, fromApplicationFd):
  476.         (toEngineOutput, toEngineInput) = os.pipe()
  477.         (fromEngineOutput, fromEngineInput) = os.pipe()
  478.         
  479.         try:
  480.             enginePID = os.fork()
  481.         except OSError:
  482.             e = None
  483.             print 'Monitor failed to fork: %s' % e.message
  484.             os._exit(1)
  485.  
  486.         if enginePID == 0:
  487.             os.close(toApplicationFd)
  488.             os.close(fromApplicationFd)
  489.             os.close(toEngineInput)
  490.             os.close(fromEngineOutput)
  491.             self._runEngine(toEngineOutput, fromEngineInput)
  492.             os._exit(0)
  493.         else:
  494.             os.close(toEngineOutput)
  495.             os.close(fromEngineInput)
  496.         inputPipes = (fromApplicationFd, fromEngineOutput)
  497.         targets = {
  498.             fromApplicationFd: toEngineInput,
  499.             fromEngineOutput: toApplicationFd }
  500.         pipes = (toApplicationFd, fromApplicationFd, toEngineInput, fromEngineOutput)
  501.         
  502.         try:
  503.             while True:
  504.                 (rfds, _, xfds) = select.select(inputPipes, [], pipes, None)
  505.                 for fd in rfds:
  506.                     data = os.read(fd, 65535)
  507.                     if len(data) == 0:
  508.                         raise OSError('End of data')
  509.                     len(data) == 0
  510.                     os.write(targets[fd], data)
  511.                 
  512.         except:
  513.             
  514.             try:
  515.                 os.kill(enginePID, signal.SIGQUIT)
  516.             except OSError:
  517.                 pass
  518.  
  519.             os._exit(0)
  520.  
  521.  
  522.  
  523.